home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / ftpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  20.2 KB  |  848 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #include "amiga/stat.h"
  6. #include "global.h"
  7. #include "config.h"
  8. #include "mbuf.h"
  9. #include "socket.h"
  10. #include "ftp.h"
  11. #include "ftpserv.h"
  12. #include "proc.h"
  13. #include "dirutil.h"
  14. #include "cmdparse.h"
  15. #include "commands.h"
  16. #include "files.h"
  17.  
  18. static void ftpserv __ARGS((int s,void *unused,void *p));
  19. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  20. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  21. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  22. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  23. static void ftp_redundant __ARGS((struct ftpserv *ftp));
  24.  
  25. int timewind __ARGS((int argc,char *argv[],void *p));
  26. int doftptdisc __ARGS((int argc, char *argv[], void *p));
  27.  
  28. /* Command table */
  29. static char *commands[] = {
  30.     "user",
  31.     "acct",
  32.     "pass",
  33.     "type",
  34.     "list",
  35.     "cwd",
  36.     "dele",
  37.     "name",
  38.     "quit",
  39.     "retr",
  40.     "stor",
  41.     "port",
  42.     "nlst",
  43.     "pwd",
  44.     "xpwd",            /* For compatibility with 4.2BSD */
  45.     "mkd ",
  46.     "xmkd",            /* For compatibility with 4.2BSD */
  47.     "xrmd",            /* For compatibility with 4.2BSD */
  48.     "rmd ",
  49.     "stru",
  50.     "mode",
  51.     NULLCHAR
  52. };
  53.  
  54. /* Response messages */
  55.  
  56. static char binwarn[]   = "100 Warning: File %s appears to be BINARY\n";
  57. static char sending[]   = "150 Open %s for %s %s (%ld Bytes)\n";
  58. static char sndrecv[]   = "150 Open %s for %s %s\n";
  59.  
  60. static char typeok[]    = "200 Type %s OK\n";
  61. static char mkdok[]     = "200 MKD ok\n";
  62. static char portok[]    = "200 Port command okay\n";
  63. static char okay[]      = "200 Ok\n";
  64. static char banner[]    = "220 %s FTP Ready - v%s\n";
  65. static char bye[]       = "221 Goodbye!\n";
  66. static char rxok[]      = "226 File received OK\n";
  67. static char txok[]      = "226 File sent OK\n";
  68. static char logged[]    = "230 %s Logged in, %s\n";
  69. static char loggeda[]   = "230 %s Logged in as anonymous, %s\n";
  70. static char deleok[]    = "250 File deleted\n";
  71. static char pwdmsg[]    = "257 \"%s\" is current directory\n";
  72. static char pwdmsg2[]   = "257- %s/.description\n257-\n";
  73.  
  74. static char givepass[]  = "331 Enter Password\n";
  75. static char givepasa[]  = "331 Please enter your email address '<user-id>@<host-name>'\n";
  76.  
  77. static char lowmem[]    = "421 System overloaded, try again later\n";
  78. static char noconn[]    = "425 Data connection reset\n";
  79.  
  80. static char unsupp[]    = "500 Unsupported command or option\n";
  81. static char badcmd[]    = "500 Unknown command\n";
  82. static char only8[]     = "501 Only logical bytesize 8 supported\n";
  83. static char badtype[]   = "501 Unknown type \"%s\"\n";
  84. static char badport[]   = "501 Bad port syntax\n";
  85. static char unimp[]     = "502 Command not yet implemented\n";
  86. static char userfirst[] = "503 Login with USER first.\n";
  87. static char notlog[]    = "530 Please log in with USER and PASS\n";
  88. static char noperm[]    = "550 Permission denied\n";
  89. static char cantopen[]  = "550 Can't read file \"%s\": %s\n";
  90. static char delefail[]  = "550 Delete failed: %s\n";
  91. static char writerr[]   = "552 Write error: %s\n";
  92. static char nodir[]     = "553 Can't read directory \"%s\": %s\n";
  93. static char cantmake[]  = "553 Can't create \"%s\": %s\n";
  94. static char notyet[]    = "555 Try Later : Access '%2d:00-%2d:59 %s' only\n";
  95.  
  96. static int Sftp = -1;    /* Prototype socket for service */
  97.  
  98. extern char *curftwin;
  99. int tt1, tt2, tnw;
  100.  
  101. #ifdef STIMEOUT
  102. int32 Ftptdiscinit = 0;
  103.  
  104. /* Set ftp redundancy timer */
  105. int
  106. doftptdisc(argc,argv,p)
  107. int argc;
  108. char *argv[];
  109. void *p;
  110. {
  111.     return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
  112. }
  113.  
  114. static void
  115. ftp_redundant(ftp)
  116. struct ftpserv *ftp;
  117. {
  118.     /* Clean up */
  119.     shutdown(ftp->control,2);
  120.     mainlog(ftp->control,"close FTP - Redundant");
  121.     close_s(ftp->control);
  122.     if(ftp->data != -1){
  123.         shutdown(ftp->data,2);
  124.         close_s(ftp->data);
  125.         ftp->data = -1;
  126.     }
  127.     return;
  128. }
  129. #endif
  130.  
  131. /* Start up FTP service */
  132. int ftpstart(argc,argv,p)
  133. int argc;
  134. char *argv[];
  135. void *p;
  136. {
  137.     struct sockaddr_in lsocket;
  138.     int s;
  139.  
  140.     if(Sftp != -1){
  141.         /* Already running! */
  142.         freeargs(argc,argv);
  143.         return 0;
  144.     }
  145.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  146.     chname(Curproc,"FTP listener");
  147.  
  148.     lsocket.sin_family = AF_INET;
  149.     lsocket.sin_addr.s_addr = INADDR_ANY;
  150.     if(argc < 2)
  151.         lsocket.sin_port = IPPORT_FTP;
  152.     else
  153.         lsocket.sin_port = atoi(argv[1]);
  154.  
  155.     freeargs(argc,argv);
  156.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  157.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  158.     listen(Sftp,1);
  159.     for(;;){
  160.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  161.             break;    /* Service is shutting down */
  162.  
  163.         if(availmem() < Memthresh){
  164.             usprintf(s,lowmem);
  165.             shutdown(s,1);
  166.         } else {
  167.             /* Spawn a server */
  168.             newproc("ftpserv",2048,ftpserv,s,NULL,NULL);
  169.         }
  170.     }
  171.     return 0;
  172. }
  173.  
  174. static void ftpserv(s,unused,p)
  175. int s;    /* Socket with user connection */
  176. void *unused;
  177. void *p;
  178. {
  179.     struct ftpserv ftp;
  180.     char **cmdp,buf[512],buf2[77],*arg,*cp,*file,*mode;
  181.     int cnt,i;
  182.     struct sockaddr_in socket;
  183.     FILE *fp;
  184.  
  185.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  186.     ftp.data = -1;
  187.  
  188.     sockowner(s,Curproc);        /* We own it now */
  189.     ftp.control = s;
  190.     /* Set default data port */
  191.     i = SOCKSIZE;
  192.     getpeername(s,(char *)&socket,&i);
  193.     socket.sin_port = IPPORT_FTPD;
  194.     ASSIGN(ftp.port,socket);
  195.  
  196. #ifdef STIMEOUT
  197.     /* Set the timeout timer - WG7J */
  198.     set_timer(&ftp.tdisc,Ftptdiscinit * 1000L);
  199.     ftp.tdisc.func = ftp_redundant;
  200.     ftp.tdisc.arg = &ftp;
  201.     start_timer(&ftp.tdisc);
  202. #endif
  203.  
  204.     mainlog(ftp.control,"open FTP");
  205.     sprintf(buf2,"%s/FTP.Before",SignOn);
  206.     if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  207.         while(fgets(buf2,sizeof(buf2),fp)) {
  208.             rip(buf2);
  209.             usprintf(ftp.control,"220- %s\n",buf2);
  210.         }
  211.         fclose(fp);
  212.     }
  213.  
  214.     usprintf(s,banner,Hostname,Version);
  215. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  216.         /* He closed on us */
  217.         goto finish;
  218.     }
  219. #ifdef STIMEOUT
  220.     /* Reset the timeout timer - WG7J */
  221.     start_timer(&ftp.tdisc);
  222. #endif
  223.     if(cnt == 0){
  224.         /* Can't be a legal FTP command */
  225.         usprintf(ftp.control,badcmd);
  226.         goto loop;
  227.     }    
  228.     rip(buf);
  229.     /* Translate entire buffer to lower case */
  230.     for(cp = buf;*cp != '\0';cp++)
  231.         *cp = tolower(*cp);
  232.     /* Find command in table; if not present, return syntax error */
  233.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  234.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  235.             break;
  236.     if(*cmdp == NULLCHAR){
  237.         usprintf(ftp.control,badcmd);
  238.         goto loop;
  239.     }
  240.     /* Allow only USER, PASS, QUIT before logging in */
  241.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  242.         switch(cmdp-commands){
  243.         case USER_CMD:
  244.         case PASS_CMD:
  245.         case QUIT_CMD:
  246.             break;
  247.         default:
  248.             usprintf(ftp.control,notlog);
  249.             goto loop;
  250.         }
  251.     }
  252.     arg = &buf[strlen(*cmdp)];
  253.     while(*arg == ' ')
  254.         arg++;
  255.  
  256.     /* Execute specific command */
  257.     switch(cmdp-commands){
  258.     case USER_CMD:
  259.         if(timewind(NULL,NULLCHAR,NULL)) {
  260.             usprintf(ftp.control,notyet,tt1,tt2,
  261.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  262.             goto finish;
  263.         }
  264.         free(ftp.username);
  265.         ftp.username = strdup(arg);
  266.         if(stricmp("anonymous",ftp.username) == 0)
  267.             usprintf(ftp.control,givepasa);
  268.         else
  269.             usprintf(ftp.control,givepass);
  270.         break;
  271.     case TYPE_CMD:
  272.         switch(arg[0]){
  273.         case 'A':
  274.         case 'a':    /* Ascii */
  275.             ftp.type = ASCII_TYPE;
  276.             usprintf(ftp.control,typeok,arg);
  277.             break;
  278.         case 'l':
  279.         case 'L':
  280.             while(*arg != ' ' && *arg != '\0')
  281.                 arg++;
  282.             if(*arg == '\0' || *++arg != '8'){
  283.                 usprintf(ftp.control,only8);
  284.                 break;
  285.             }
  286.             ftp.type = LOGICAL_TYPE;
  287.             ftp.logbsize = 8;
  288.             usprintf(ftp.control,typeok,arg);
  289.             break;
  290.         case 'B':
  291.         case 'b':    /* Binary */
  292.         case 'I':
  293.         case 'i':    /* Image */
  294.             ftp.type = IMAGE_TYPE;
  295.             usprintf(ftp.control,typeok,arg);
  296.             break;
  297.         default:    /* Invalid */
  298.             usprintf(ftp.control,badtype,arg);
  299.             break;
  300.         }
  301.         break;
  302.     case QUIT_CMD:
  303.         usprintf(ftp.control,bye);
  304.         goto finish;
  305.     case RETR_CMD:
  306.         if(timewind(NULL,NULLCHAR,NULL)) {
  307.             usprintf(ftp.control,notyet,tt1,tt2,
  308.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  309.             goto finish;
  310.         }
  311.         file = pathname(ftp.cd,arg);
  312.         switch(ftp.type){
  313.         case IMAGE_TYPE:
  314.         case LOGICAL_TYPE:
  315.             mode = READ_BINARY;
  316.             break;
  317.         case ASCII_TYPE:
  318.             mode = READ_TEXT;
  319.             break;
  320.         }
  321.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  322.              usprintf(ftp.control,noperm);
  323.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  324.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  325.         } else {
  326.             mainlog(ftp.control,"RETR %s",file);
  327.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  328.                 usprintf(ftp.control,binwarn,file);
  329.             }
  330.             sendit(&ftp,"RETR",file);
  331.         }
  332.         free(file);
  333.         break;
  334.     case STOR_CMD:
  335.         if(timewind(NULL,NULLCHAR,NULL)) {
  336.             usprintf(ftp.control,notyet,tt1,tt2,
  337.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  338.             goto finish;
  339.         }
  340.         file = pathname(ftp.cd,arg);
  341.         switch(ftp.type){
  342.         case IMAGE_TYPE:
  343.         case LOGICAL_TYPE:
  344.             mode = WRITE_BINARY;
  345.             break;
  346.         case ASCII_TYPE:
  347.             mode = WRITE_TEXT;
  348.             break;
  349.         }
  350.         if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  351.              usprintf(ftp.control,noperm);
  352.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  353.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  354.         } else {
  355.             mainlog(ftp.control,"STOR %s",file);
  356.             recvit(&ftp,"STOR",file);
  357.         }
  358.         free(file);
  359.         break;
  360.     case PORT_CMD:
  361.         if(pport(&ftp.port,arg) == -1){
  362.             usprintf(ftp.control,badport);
  363.         } else {
  364.             usprintf(ftp.control,portok);
  365.         }
  366.         break;
  367.     case LIST_CMD:
  368.         file = pathname(ftp.cd,arg);
  369.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  370.              usprintf(ftp.control,noperm);
  371.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  372.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  373.         } else {
  374.             sendit(&ftp,"LIST",file);
  375.         }
  376.         free(file);
  377.         break;
  378.     case NLST_CMD:
  379.         file = pathname(ftp.cd,arg);
  380.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  381.              usprintf(ftp.control,noperm);
  382.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  383.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  384.         } else {
  385.             sendit(&ftp,"NLST",file);
  386.         }
  387.         free(file);
  388.         break;
  389.     case CWD_CMD:
  390.         file = pathname(ftp.cd,arg);
  391.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  392.              usprintf(ftp.control,noperm);
  393.             free(file);
  394.         } else if(access(file,0) == 0){    /* See if it exists */
  395.             /* Succeeded, record in control block */
  396.             free(ftp.cd);
  397.             ftp.cd = file;
  398.             sprintf(buf2,"%s/.description",file);
  399.             if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  400.                 usprintf(ftp.control,pwdmsg2,file);
  401.                 while(fgets(buf2,sizeof(buf2),fp)) {
  402.                     rip(buf2);
  403.                     usprintf(ftp.control,"257- %s\n",buf2);
  404.                 }
  405.                 usprintf(ftp.control,"257- \n");
  406.                 fclose(fp);
  407.             } 
  408.             usprintf(ftp.control,pwdmsg,file);
  409.         } else {
  410.             /* Failed, don't change anything */
  411.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  412.             free(file);
  413.         }
  414.         break;
  415.     case XPWD_CMD:
  416.     case PWD_CMD:
  417.         usprintf(ftp.control,pwdmsg,ftp.cd);
  418.         break;
  419.     case ACCT_CMD:        
  420.         usprintf(ftp.control,unimp);
  421.         break;
  422.     case DELE_CMD:
  423.         file = pathname(ftp.cd,arg);
  424.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  425.              usprintf(ftp.control,noperm);
  426.         } else if(unlink(file) == 0){
  427.             mainlog(ftp.control,"DELE %s",file);
  428.             usprintf(ftp.control,deleok);
  429.         } else {
  430.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  431.         }
  432.         free(file);
  433.         break;
  434.     case PASS_CMD:
  435.         if(ftp.username == NULLCHAR)
  436.             usprintf(ftp.control,userfirst);
  437.         else
  438.             ftplogin(&ftp,arg);            
  439.         break;
  440.     case XMKD_CMD:
  441.     case MKD_CMD:
  442.         file = pathname(ftp.cd,arg);
  443.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  444.             usprintf(ftp.control,noperm);
  445.         } else if(mkdir(file) == 0){
  446.             mainlog(ftp.control,"MKD %s",file);
  447.             usprintf(ftp.control,mkdok);
  448.         } else {
  449.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  450.         }
  451.         free(file);
  452.         break;
  453.     case XRMD_CMD:
  454.     case RMD_CMD:
  455.         file = pathname(ftp.cd,arg);
  456.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  457.              usprintf(ftp.control,noperm);
  458.         } else if(rmdir(file) == 0){
  459.             mainlog(ftp.control,"RMD %s",file);
  460.             usprintf(ftp.control,deleok);
  461.         } else {
  462.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  463.         }
  464.         free(file);
  465.         break;
  466.     case STRU_CMD:
  467.         if(tolower(arg[0]) != 'f')
  468.             usprintf(ftp.control,unsupp);
  469.         else
  470.             usprintf(ftp.control,okay);
  471.         break;
  472.     case MODE_CMD:
  473.         if(tolower(arg[0]) != 's')
  474.             usprintf(ftp.control,unsupp);
  475.         else
  476.             usprintf(ftp.control,okay);
  477.         break;
  478.     }
  479.     goto loop;
  480. finish:
  481.  
  482. #ifdef STIMEOUT
  483.     stop_timer(&ftp.tdisc);
  484. #endif
  485.  
  486.     mainlog(ftp.control,"close FTP");
  487.     /* Clean up */
  488.     close_s(ftp.control);
  489.     if(ftp.data != -1)
  490.         close_s(ftp.data);
  491.     if(ftp.fp != NULLFILE)
  492.         fclose(ftp.fp);
  493.     free(ftp.username);
  494.     free(ftp.path);
  495.     free(ftp.cd);
  496. }
  497.  
  498. /* Shut down FTP server */
  499. int ftp0(argc,argv,p)
  500. int argc;
  501. char *argv[];
  502. void *p;
  503. {
  504.     close_s(Sftp);
  505.     Sftp = -1;
  506.     return 0;
  507. }
  508.  
  509. static int pport(sock,arg)
  510. struct sockaddr_in *sock;
  511. char *arg;
  512. {
  513.     int32 n;
  514.     int i;
  515.  
  516.     n = 0;
  517.     for(i=0;i<4;i++){
  518.         n = atoi(arg) + (n << 8);
  519.         if((arg = strchr(arg,',')) == NULLCHAR)
  520.             return -1;
  521.         arg++;
  522.     }
  523.     sock->sin_addr.s_addr = n;
  524.     n = atoi(arg);
  525.     if((arg = strchr(arg,',')) == NULLCHAR)
  526.         return -1;
  527.     arg++;
  528.     n = atoi(arg) + (n << 8);
  529.     sock->sin_port = n;
  530.     return 0;
  531. }
  532.  
  533. /* Subroutine for logging in the user whose name is name and
  534.    password is pass.  The buffer path should be long enough to
  535.    keep a line from the userfile.  If pwdignore is true, the
  536.    password check will be overridden.  The return value is the
  537.    permissions field or -1 if the login failed.  Path is set to
  538.    point at the path field, and pwdignore will be true if no
  539.    particular password was needed for this user.
  540.  */
  541. int userlogin(name,pass,path,len,pwdignore)
  542. char *name;
  543. char *pass;
  544. char **path;
  545. int len;            /* Length of buffer pointed at by *path */
  546. int *pwdignore;
  547. {
  548.     char *cp,*cp1;
  549.     FILE *fp;
  550.     char *anonymous = NULLCHAR;
  551.     int anony, perm;
  552.  
  553.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE)
  554.         /* Userfile doesn't exist */
  555.         return -1;
  556.     while(fgets(*path,len,fp),!feof(fp)){
  557.         if(*path[0] == '#')
  558.             continue;    /* Comment */
  559.         if((cp = strchr(*path,' ')) == NULLCHAR)
  560.             /* Bogus entry */
  561.             continue;
  562.         *cp++ = '\0';        /* Now points to password */
  563.         if(stricmp(name,*path) == 0)
  564.             break;        /* Found user name */
  565.         if(stricmp("anonymous",*path) == 0)
  566.             anonymous = strdup(cp); /* remember anon entry */
  567.     }
  568.     if((anonymous == NULLCHAR) && (feof(fp))) {
  569.         /* User not in file, nor was anonymous */
  570.         fclose(fp);
  571.         return -1;
  572.     }
  573.      if(feof(fp)){
  574.         /* restore anonymous */
  575.         strcpy(cp = *path, anonymous);
  576.     }
  577.     fclose(fp);
  578.     /* Look for space after password field in file */
  579.     if((cp1 = strchr(cp,' ')) == NULLCHAR)
  580.         /* Invalid file entry */
  581.         return -1;
  582.     *cp1++ = '\0';    /* Now points to path field */
  583.     anony = *pwdignore;
  584.     if(strcmp(cp,"*") == 0)
  585.         anony = 1;    /* User ID is password-free */
  586.     if(!anony && strcmp(cp,pass) != 0)
  587.         /* Password required, but wrong one given */
  588.         return -1;
  589.     if((cp = strchr(cp1,' ')) == NULLCHAR)
  590.         /* Permission field missing */
  591.         return -1;
  592.     *cp++ = '\0';    /* now points to permission field */
  593.     perm = atoi(cp);
  594. /*
  595.  *  Well, on the Amiga, a file can be referenced by many names:
  596.  *  device names (DF0:) or volume names (My_Disk:).  This hunk of code
  597.  *  passed the pathname specified in the ftpusers file, and gets the
  598.  *  absolute path copied into the user's buffer.  We really should just
  599.  *  allocate the buffer and return a pointer to it, since the caller
  600.  *  really doesn't have a good idea how long the path string is..
  601.  */
  602.     cp1 = pathname("", cp1);
  603.     if (cp1)
  604.         strcpy(*path, cp1);
  605.     else
  606.         **path = '\0';
  607.     free(cp1);
  608.     *pwdignore = anony;
  609.     /* Finally return the permission bits */
  610.     return perm;
  611. }
  612.     
  613. /* Attempt to log in the user whose name is in ftp->username and password
  614.  * in pass
  615.  */
  616. static void ftplogin(ftp,pass)
  617. struct ftpserv *ftp;
  618. char *pass;
  619. {
  620.     long t;
  621.     char *path,buf2[77],*cp,*cp1;
  622.     int anony = 0;
  623.     FILE *fp;
  624.  
  625.     path = mallocw(200);
  626.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  627.        == -1){
  628.         usprintf(ftp->control,noperm);
  629.         free(path);
  630.         return;
  631.     }
  632.     /* Set up current directory and path prefix */
  633.     ftp->cd = path;
  634.     ftp->path = strdup(path);
  635.  
  636.     sprintf(buf2,"%s/FTP.After",SignOn);
  637.     if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  638.         while(fgets(buf2,sizeof(buf2),fp)) {
  639.             rip(buf2);
  640.             usprintf(ftp->control,"230- %s\n",buf2);
  641.         }
  642.         fclose(fp);
  643.     }
  644.  
  645.     time(&t);
  646.     cp = ctime(&t);
  647.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  648.         *cp1 = '\0';
  649.  
  650.     if(!anony) {
  651.         usprintf(ftp->control,logged,ftp->username,cp);
  652.         mainlog(ftp->control,"%s logged in",ftp->username);
  653.     } else {
  654.         usprintf(ftp->control,loggeda,
  655.             strcmp(ftp->username,"anonymous") ? 
  656.             ftp->username : "",cp);
  657.         mainlog(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  658.     }
  659. }        
  660.  
  661. /* Return 1 if the file operation is allowed, 0 otherwise */
  662. int permcheck(path,perms,op,file)
  663. char *path;
  664. int perms;
  665. int op;
  666. char *file;
  667. {
  668.     if(file == NULLCHAR || path == NULLCHAR)
  669.         return 0;    /* Probably hasn't logged in yet */
  670.  
  671.     /* The target file must be under the user's allowed search path */
  672.     if(strncmp(file,path,strlen(path)) != 0)
  673.         return 0;
  674.  
  675.     switch(op){
  676.     case RETR_CMD:
  677.         /* User must have permission to read files */
  678.         if(perms & FTP_READ)
  679.             return 1;
  680.         return 0;
  681.     case DELE_CMD:
  682.     case RMD_CMD:
  683.         /* User must have permission to (over)write files */
  684.         if(perms & FTP_WRITE)
  685.             return 1;
  686.         return 0;
  687.     case STOR_CMD:
  688.     case MKD_CMD:
  689.         /* User must have permission to (over)write files, or permission
  690.          * to create them if the file doesn't already exist
  691.          */
  692.         if(perms & FTP_WRITE)
  693.             return 1;
  694.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  695.             return 1;
  696.         return 0;
  697.     }
  698.     return 0;    /* "can't happen" -- keep lint happy */
  699. }
  700.  
  701. static int sendit(ftp,command,file)
  702. struct ftpserv *ftp;
  703. char *command;
  704. char *file;
  705. {
  706.     long total;
  707.     struct sockaddr_in dport;
  708.     struct stat stb;
  709.  
  710.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  711.     dport.sin_family = AF_INET;
  712.     dport.sin_addr.s_addr = INADDR_ANY;
  713.     dport.sin_port = IPPORT_FTPD;
  714.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  715.     stat(file,&stb);
  716.     usprintf(ftp->control, (command == "LIST") || (command == "NLST")
  717.         ? sndrecv : sending, file, ftp->type ? "BINARY" : "ASCII",
  718.         command, stb.st_size);
  719.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  720.         fclose(ftp->fp);
  721.         ftp->fp = NULLFILE;
  722.         close_s(ftp->data);
  723.         ftp->data = -1;
  724.         usprintf(ftp->control,noconn);
  725.         return -1;
  726.     }
  727. #ifdef STIMEOUT
  728.     /* Turn of the timeout timer here, some ftp's could
  729.      * take a long time with sloooow packet channels - WG7J
  730.      */
  731.     stop_timer(&ftp->tdisc);
  732. #endif
  733.     /* Do the actual transfer */
  734.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  735.  
  736. #ifdef STIMEOUT
  737.     /* And turn it back on now */
  738.     start_timer(&ftp->tdisc);
  739. #endif
  740.     if(total == -1){
  741.         /* An error occurred on the data connection */
  742.         usprintf(ftp->control,noconn);
  743.         shutdown(ftp->data,2);    /* Blow away data connection */
  744.     } else {
  745.         usprintf(ftp->control,txok);
  746.     }
  747.     fclose(ftp->fp);
  748.     ftp->fp = NULLFILE;
  749.     close_s(ftp->data);
  750.     ftp->data = -1;
  751.     if(total == -1)
  752.         return -1;
  753.     else
  754.         return 0;
  755. }
  756.  
  757. static int recvit(ftp,command,file)
  758. struct ftpserv *ftp;
  759. char *command;
  760. char *file;
  761. {
  762.     struct sockaddr_in dport;
  763.     long total;
  764.  
  765.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  766.     dport.sin_family = AF_INET;
  767.     dport.sin_addr.s_addr = INADDR_ANY;
  768.     dport.sin_port = IPPORT_FTPD;
  769.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  770.     usprintf(ftp->control, sndrecv, file,
  771.         ftp->type ? "BINARY" : "ASCII", command);
  772.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  773.         fclose(ftp->fp);
  774.         ftp->fp = NULLFILE;
  775.         close_s(ftp->data);
  776.         ftp->data = -1;
  777.         usprintf(ftp->control,noconn);
  778.         return -1;
  779.     }
  780. #ifdef STIMEOUT
  781.     /* Turn of the timeout timer here; some ftp's could
  782.      * take a long time with sloooow packet channels - WG7J
  783.      */
  784.     stop_timer(&ftp->tdisc);
  785. #endif
  786.  
  787.     /* Do the actual transfer */
  788.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  789.  
  790. #ifdef STIMEOUT
  791.     /* And turn it back on now */
  792.     start_timer(&ftp->tdisc);
  793. #endif
  794.  
  795.     if(total == -1) {
  796.         /* An error occurred while writing the file */
  797.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  798.         shutdown(ftp->data,2);    /* Blow it away */
  799.     } else {
  800.         usprintf(ftp->control,rxok);
  801.         close_s(ftp->data);
  802.     }
  803.     ftp->data = -1;
  804.     fclose(ftp->fp);
  805.     ftp->fp = NULLFILE;
  806.     if(total == -1)
  807.         return -1;
  808.     else
  809.         return 0;
  810. }
  811.  
  812. /* This checks the current time is in a preset Time-Window before
  813.    allowing a user to login */
  814. int timewind(argc,argv,p)
  815. int argc;
  816. char *argv[];
  817. void *p;
  818. {
  819.     char *now;
  820.     long t;
  821.     char *t1, *t2;
  822.  
  823.     t1 = strdup(curftwin);
  824.     *(t1 + 2) = '\0';
  825.     tt1 = atoi(t1);
  826.  
  827.     t2 = strdup(curftwin+2);
  828.     *(t2 + 2) = '\0';
  829.     tt2 = atoi(t2);
  830.  
  831.     time(&t);
  832.     now = ctime(&t) + 11;
  833.     *(now + 2) = '\0';
  834.     tnw = atoi(now);
  835.  
  836.     if(tt1 > tt2) {
  837.         if(((tnw >= tt1) && (tnw <= 23)) ||
  838.            ((tnw <= tt2) && (tnw >= 0)))
  839.             return 0;        /* right in time */
  840.     } else {
  841.         if((tnw >= tt1) && (tnw <= tt2))
  842.             return 0;        /* right in time */
  843.     }
  844.  
  845.     return 1;
  846. }
  847.  
  848.